package EEG;

import gnu.io.CommPort;
import gnu.io.CommPortIdentifier;
import gnu.io.SerialPort;

import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.FileDescriptor;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Scanner;

import uk.org.toot.audio.core.AudioBuffer;
import uk.org.toot.audio.core.AudioProcess;

public class SerialComm implements AudioProcess {

	private InputStream in;
	private DataInputStream din;
	public SerialPort serialPort;
	public BufferedWriter out;


	public SerialComm() {
		super();
	}

	void connect(String portName) throws Exception {
		// Works until 2038 on 32-bit systems..
		long now = System.currentTimeMillis();
		try {
			CommPortIdentifier portIdentifier = CommPortIdentifier
					.getPortIdentifier(portName);
			if (portIdentifier.isCurrentlyOwned()) {
				System.out.println("Error: Port is currently in use");
			} else {
				CommPort commPort = portIdentifier.open(this.getClass().getName(),
						2000);

				if (commPort instanceof SerialPort) {
					serialPort = (SerialPort) commPort;
					serialPort.setSerialPortParams(9600, SerialPort.DATABITS_8,
							SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);

					in = serialPort.getInputStream();
					
					FileWriter fstream = new FileWriter(now + ".eeg");
					out = new BufferedWriter(fstream);
					
					// // OutputStream out = serialPort.getOutputStream();
					//
					// (new Thread(new SerialReader(in))).start();
					// // (new Thread(new SerialWriter(out))).start();

				} else {
					System.out
							.println("Error: Only serial ports are handled by this example.");
				}
			}
			din = new DataInputStream(in);
		} catch (Exception e) {
			System.out.println("Error: Un-able to open port, check name");
			e.printStackTrace();
		}

	}

	/** */
	public static class SerialReader implements Runnable {
		InputStream in;

		public SerialReader(InputStream in) {
			this.in = in;
		}

		public void run() {
			byte[] buffer = new byte[1024];
			int len = -1;
			try {
				while ((len = this.in.read(buffer)) > -1) {
					System.out.print(new String(buffer, 0, len));
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	static void listPorts() {
		java.util.Enumeration<CommPortIdentifier> portEnum = CommPortIdentifier
				.getPortIdentifiers();
		while (portEnum.hasMoreElements()) {
			CommPortIdentifier portIdentifier = portEnum.nextElement();
			System.out.println(portIdentifier.getName() + " - "
					+ getPortTypeName(portIdentifier.getPortType()));
		}
	}

	static String getPortTypeName(int portType) {
		switch (portType) {
		case CommPortIdentifier.PORT_I2C:
			return "I2C";
		case CommPortIdentifier.PORT_PARALLEL:
			return "Parallel";
		case CommPortIdentifier.PORT_RAW:
			return "Raw";
		case CommPortIdentifier.PORT_RS485:
			return "RS485";
		case CommPortIdentifier.PORT_SERIAL:
			return "Serial";
		default:
			return "unknown type";
		}
	}

	public static void main(String[] args) {
		try {
			listPorts();
			SerialComm comm = new SerialComm();
			comm.connect("COM40");
			System.out.println(comm);
			((CommPort)comm.serialPort).setInputBufferSize(1000);
			System.out.println("Buffer Size = " + ((CommPort)comm.serialPort).getInputBufferSize());
			(new Thread(new SerialReader(comm.in))).start();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	@Override
	public void close() throws Exception {
		out.close();
		// TODO Auto-generated method stub

	}

	@Override
	public void open() throws Exception {
		// TODO Auto-generated method stub

	}

	byte[] buff = new byte[1000];

	short last_val=0;
	boolean first=true;
	
	@Override
	public int processAudio(AudioBuffer arg0) {

		int n = arg0.getSampleCount();

		int count = 0;
		float buff[]=arg0.getChannel(0);
		byte b2[]=new byte[2];
		byte lsb;
		byte msb;
		
		while (count < n) {
			short val = 0;
			try {
				while(in.available() <2) {
					try {
						//System.out.println(" Sleep yawn");
						Thread.sleep(1);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				
				int ret=in.read(b2,0,2);
				
				val = (short) ((((b2[0] & 0xff)<<8) + (0xff & b2[1])));
				//System.out.println(val);
				
				if (((val & 0xC0) == 0xC0)&&((val & 0xC000) == 0x00))
				{
					lsb = (byte) (val & 0x3F); // Lower 6 bits
					msb = (byte) ((val >> 8) & 0x3F);
					val = (short) (lsb + (msb << 6));
					
					// Restore sign bits (we used them for byte order data)...
					if ((val & 0x800) == 0x800)
					{
						val = (short) (val | 0xF000);
					}
					
					//buff[count] = (float) (val/4096.0); // UnSigned Short
					buff[count] = (float) ((val + 2048)/4096.0); //Signed Short
	
					out.write(String.valueOf(buff[count]));
					out.write(", ");
					
					//System.out.println(val);
				}
				else
				{
					in.read(b2,0,1);
				}
//					
				
				//System.out.println(buff[count]);
				last_val= (short) (val+1);
				count++;
			} catch (IOException e) {
				// TODO Auto-generated catch block
				//e.printStackTrace();
			}
			
			
				
//			}
		}
		//System.out.println();
		
		return 0;
	}
}